#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <functional>
#include "Log.hpp"
#include "InetAddr.hpp"
#include "Dict.hpp"

const int gsocketfd = -1;
const uint16_t glocalport = 8888;

enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR
};

using func_t = function<std::string(std::string)>;
class UDPServer
{
public:
    UDPServer(func_t func, uint16_t localport = glocalport)
        : _func(func),
          _localport(localport),
          _isrunning(false),
          _socketfd(gsocketfd)
    {
    }
    ~UDPServer()
    {
        if (_socketfd > gsocketfd)
        {
            close(_socketfd);
        }
    }
    void Init()
    {
        // 创建UDP文件
        _socketfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_socketfd < 0)
        {
            LOG(FATAL, "create socket error\n");
            exit(SOCKET_ERROR);
        }
        LOG(DEBUG, "create socket success,socketfd:%d\n", _socketfd);

        // bind
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_localport);
        local.sin_addr.s_addr = INADDR_ANY;
        int n = bind(_socketfd, (struct sockaddr *)&local, sizeof(local));
        if (n < 0)
        {
            LOG(FATAL, "bind error\n");
            exit(BIND_ERROR);
        }
        LOG(DEBUG, "bind success!\n");
    }
    void Start()
    {
        _isrunning = true;
        char buffer[1024];
        while (_isrunning)
        {
            struct sockaddr_in peer;
            socklen_t len;
            int n = recvfrom(_socketfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
            if (n > 0)
            {
                InetAddr addr(peer);
                buffer[n] = '\0';
                std::string value = _func(buffer);
                sendto(_socketfd, value.c_str(), value.size(), 0, (struct sockaddr *)&peer, len);
            }
            else
            {
                std::cout << "Server recvfrom ,  error" << std::endl;
            }
        }
    }

private:
    int _socketfd;
    uint16_t _localport;
    func_t _func;
    bool _isrunning;
};